package auth

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"things_iot_backend/cache"
	"things_iot_backend/config"
	"things_iot_backend/models"

	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"
)

var jwtSecret []byte

type Claims struct {
	UserID   uint   `json:"user_id"`
	Username string `json:"username"`
	Role     string `json:"role"`
	jwt.RegisteredClaims
}

func InitJWT(cfg *config.Config) {
	jwtSecret = []byte(cfg.JWTSecret)
}

// GenerateToken 生成JWT令牌
func GenerateToken(user *models.User) (string, error) {
	expirationTime := time.Now().Add(24 * time.Hour)

	claims := &Claims{
		UserID:   user.ID,
		Username: user.Username,
		Role:     user.Role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expirationTime),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			Issuer:    "things_iot_platform",
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(jwtSecret)
}

// ValidateToken 验证JWT令牌
func ValidateToken(tokenString string) (*Claims, error) {
	// 检查令牌是否在黑名单中
	blacklisted, err := cache.IsJWTBlacklisted(tokenString)
	if err != nil {
		return nil, err
	}
	if blacklisted {
		return nil, errors.New("token is blacklisted")
	}

	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return jwtSecret, nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid token")
}

// ExtractTokenFromHeader 从请求头中提取令牌
func ExtractTokenFromHeader(authHeader string) (string, error) {
	if authHeader == "" {
		return "", errors.New("authorization header is required")
	}

	parts := strings.Split(authHeader, " ")
	if len(parts) != 2 || parts[0] != "Bearer" {
		return "", errors.New("authorization header format must be Bearer {token}")
	}

	return parts[1], nil
}

// HashPassword 哈希密码
func HashPassword(password string) (string, error) {
	bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	return string(bytes), err
}

// CheckPassword 验证密码
func CheckPassword(password, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

// InvalidateToken 使令牌失效（加入黑名单）
func InvalidateToken(tokenString string) error {
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return err
	}

	// 计算令牌剩余的有效时间
	expiry := time.Until(claims.ExpiresAt.Time)
	if expiry <= 0 {
		return nil // 令牌已过期，无需加入黑名单
	}

	return cache.CacheJWTBlacklist(tokenString, expiry)
}

// GenerateMQTTPassword 生成MQTT密码
func GenerateMQTTPassword(deviceID, mqttUsername, secretKey string) (string, error) {
	// 使用HMAC-SHA256算法生成密码
	// 在实际实现中，您可能需要使用crypto/hmac包
	// 这里简化实现，实际使用时请使用安全的HMAC实现
	data := deviceID + mqttUsername + secretKey
	hashed, err := bcrypt.GenerateFromPassword([]byte(data), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}
	return string(hashed), nil
}

// VerifyMQTTPassword 验证MQTT密码
func VerifyMQTTPassword(password, deviceID, mqttUsername, secretKey string) bool {
	data := deviceID + mqttUsername + secretKey
	return CheckPassword(data, password)
}

// GetUserFromToken 从令牌中获取用户信息
func GetUserFromToken(tokenString string) (*Claims, error) {
	return ValidateToken(tokenString)
}

// IsSuperAdmin 检查用户是否为超级管理员
func IsSuperAdmin(claims *Claims) bool {
	return claims.Role == "super_admin"
}

// CanAccessDevice 检查用户是否有权访问设备
func CanAccessDevice(claims *Claims, deviceUserID uint) bool {
	// 超级管理员可以访问所有设备
	if IsSuperAdmin(claims) {
		return true
	}
	// 普通用户只能访问自己的设备
	return claims.UserID == deviceUserID
}

// GenerateRefreshToken 生成刷新令牌（可选功能）
func GenerateRefreshToken(user *models.User) (string, error) {
	expirationTime := time.Now().Add(7 * 24 * time.Hour) // 7天有效期

	claims := &Claims{
		UserID:   user.ID,
		Username: user.Username,
		Role:     user.Role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expirationTime),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			Issuer:    "things_iot_platform_refresh",
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(jwtSecret)
}

// ValidateRefreshToken 验证刷新令牌
func ValidateRefreshToken(tokenString string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return jwtSecret, nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid refresh token")
}

// GenerateDeviceCredentials 生成设备MQTT凭证
func GenerateDeviceCredentials(deviceID string, secretKey string) (string, string, error) {
	mqttUsername := fmt.Sprintf("things_iot_%s", deviceID)
	mqttPassword, err := GenerateMQTTPassword(deviceID, mqttUsername, secretKey)
	if err != nil {
		return "", "", err
	}
	return mqttUsername, mqttPassword, nil
}

// VerifyDeviceCredentials 验证设备MQTT凭证
func VerifyDeviceCredentials(deviceID, username, password, secretKey string) bool {
	expectedUsername := fmt.Sprintf("things_iot_%s", deviceID)
	if username != expectedUsername {
		return false
	}
	return VerifyMQTTPassword(password, deviceID, username, secretKey)
}
